<template>
	<div ref="statsRef" class="statistics"></div>
	<div ref="containerRef" class="container"></div>
	<audio ref="audioRef" class="car-player" :src="BlueFields" loop></audio>
</template>

<script lang="ts" setup>
import {onMounted, ref, watch, watchEffect} from 'vue';
import Stats from 'stats.js';
import {AxesHelper, Color, MeshBasicMaterial, PerspectiveCamera, PlaneGeometry, Scene, WebGLRenderer, Mesh, BoxGeometry, SphereGeometry, SpotLight, MeshLambertMaterial, MeshPhongMaterial, DoubleSide, PointLight, AmbientLight, CameraHelper, DirectionalLight, ACESFilmicToneMapping, EquirectangularReflectionMapping, Fog, GridHelper, MeshPhysicalMaterial, MeshStandardMaterial, Vector2, Raycaster} from 'three';
import type {Material, Object3D} from 'three';
import {RGBELoader} from 'three/examples/jsm/loaders/RGBELoader';
import * as dat from 'dat.gui';
import { DRACOLoader } from 'three/examples/jsm/Addons.js';
import { GLTFLoader, type GLTF } from 'three/examples/jsm/loaders/GLTFLoader.js';
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls.js';
// import minedump_flats_1k from '../../assets/minedump_flats_1k.hdr?url';
import Toyota from '../../assets/low_poly_toyota_supra_jza80_mark4_1994.glb?url';
import BlueFields from '../../assets/Blue_Fields.mp3';

const stats = new Stats();

stats.showPanel(0);

const statsRef = ref<HTMLDivElement>();
const containerRef = ref<HTMLDivElement>();
const audioRef = ref<HTMLAudioElement>();
const scene = new Scene();
const grid = new GridHelper(20, 40, 0xffffff, 0xffffff);
const rendererRef = ref<WebGLRenderer>();
const cameraRef = ref<PerspectiveCamera>();
//平行光
const directionalLight = new DirectionalLight(0xffffff, 1);

directionalLight.position.set(5, 5, 5).normalize();
/* directionalLight.castShadow = true;
directionalLight.intensity = 0.5; */
scene.add(directionalLight);

const ambientLight = new AmbientLight(0x404040); // 环境光

scene.add(ambientLight);

const controlRef = ref({
	bodyColor: '#0c0c0c',
	glassColor: '#0c0c0c',
	detailsColor: '#0c0c0c',
	speed: 1000,
	showGrid: true,
	playMusic: false,
});

const orbitControlsRef = ref<OrbitControls>();

const bodyMaterial = new MeshPhysicalMaterial({
	color: 0xff0000,
	metalness: 1.0,
	roughness: 0.5,
	clearcoat: 1.0,
	clearcoatRoughness: 0.03,
	// clearcoatRoughness: 0,
	sheen: 0.5,
	
	transparent: false,
	opacity: 1.0,
});

const glassMaterial = new MeshPhysicalMaterial({
	color: 0xffffff,
	metalness: 0.25,
	roughness: 0,
	transmission: 1.0,
});

const detailsMaterial = new MeshStandardMaterial({
	color: 0xffffff,
	metalness: 1.0,
	roughness: 0.5,
});

function initGUI(){
	if(document.querySelectorAll('.dg.ac>.dg.main.a').length === 0){
		//还未初始化图形用户界面
		window.gui = new dat.GUI();
		window.gui.addColor(controlRef.value, 'bodyColor');
		window.gui.addColor(controlRef.value, 'detailsColor');
		window.gui.addColor(controlRef.value, 'glassColor');
		window.gui.add(controlRef.value, 'speed', 250, 2000);
		window.gui.add(controlRef.value, 'showGrid');
		window.gui.add(controlRef.value, 'playMusic');
	}
}

initGUI();

function initCamera(){
	cameraRef.value = new PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
	
	cameraRef.value.position.set(-30, 40, 30);
	cameraRef.value.lookAt(scene.position);
}

function initRenderer(){
	rendererRef.value = new WebGLRenderer({
		antialias: true,
	});
	
	rendererRef.value.setSize(window.innerWidth, window.innerHeight);
	rendererRef.value.setPixelRatio(window.devicePixelRatio);
	// rendererRef.value.outputEncoding = sRGBEncoding;
	rendererRef.value.toneMapping = ACESFilmicToneMapping;
	rendererRef.value.toneMappingExposure = 0.85;
}

async function initScene(){
	scene.background = new Color(0x333333);
	// scene.environment = new RGBELoader().load(minedump_flats_1k);
	// scene.environment = new RGBELoader().load('/minedump_flats_1k.hdr');
	
	const loader = new RGBELoader();
	
	scene.environment = await loader.loadAsync('/minedump_flats_1k.hdr');
	scene.environment!.mapping = EquirectangularReflectionMapping;
	// scene.fog = new Fog(0x333333, 10, 15);
	scene.fog = new Fog(0x333333, 0.015, 100);
	
	const material = grid.material as Material;
	
	material.opacity = 0.2;
	material.depthWrite = false;
	material.transparent = true;
	scene.add(grid);
	
	const axes = new AxesHelper(20);
	
	scene.add(axes);
}

const wheels: (Object3D | undefined)[] = [];
const carRef = ref<Object3D>();

function initGLTF(){
	const dracoLoader = new DRACOLoader();
	
	dracoLoader.setDecoderPath('/gltf/');
	
	const loader = new GLTFLoader();
	
	loader.setDRACOLoader(dracoLoader);
	
	loader.load(Toyota, (gltf: GLTF) => {
		console.log('gltf:');
		console.log(gltf);
		
		const carModel = gltf.scene.children[0];
		
		carModel.scale.set(.2, .2, .2);
		carModel.rotation.z = Math.PI;
		
		// (carModel.getObjectByName('Object_4') as Mesh).material = glassMaterial;
		(carModel.getObjectByName('Object_4') as Mesh).material.color.set(0xffffff);
		(carModel.getObjectByName('Object_4') as Mesh).material.metalness = 0.25;
		(carModel.getObjectByName('Object_4') as Mesh).material.roughness = 0;
		(carModel.getObjectByName('Object_4') as Mesh).material.ior = 1.5;
		console.log('glassMaterial:');
		console.log(glassMaterial);
		(carModel.getObjectByName('Object_9') as Mesh).material = glassMaterial;
		
		// (carModel.getObjectByName('Object_13') as Mesh).material = glassMaterial;
		(carModel.getObjectByName('Object_13') as Mesh).material.color.set(0xffffff);
		(carModel.getObjectByName('Object_13') as Mesh).material.metalness = 0.25;
		(carModel.getObjectByName('Object_13') as Mesh).material.roughness = 0;
		(carModel.getObjectByName('Object_13') as Mesh).material.ior = 1.5;
		
		// (carModel.getObjectByName('Object_14') as Mesh).material = glassMaterial;
		(carModel.getObjectByName('Object_14') as Mesh).material.color.set(0xffffff);
		(carModel.getObjectByName('Object_14') as Mesh).material.metalness = 0.25;
		(carModel.getObjectByName('Object_14') as Mesh).material.roughness = 0;
		(carModel.getObjectByName('Object_14') as Mesh).material.ior = 1.5;
		console.log('detailsMaterial:');
		console.log(detailsMaterial);
		(carModel.getObjectByName('Object_5') as Mesh).material = detailsMaterial;
		(carModel.getObjectByName('Object_6') as Mesh).material = detailsMaterial;
		(carModel.getObjectByName('Object_10') as Mesh).material = detailsMaterial;
		(carModel.getObjectByName('Object_12') as Mesh).material = detailsMaterial;
		
		/* (carModel.getObjectByName('Object_7') as Mesh).material = null;
		(carModel.getObjectByName('Object_7') as Mesh).material = bodyMaterial; */
		(carModel.getObjectByName('Object_7') as Mesh).material.color.set(0xff0000);
		(carModel.getObjectByName('Object_7') as Mesh).material.metalness = 1;
		(carModel.getObjectByName('Object_7') as Mesh).material.roughness = 0.5;
		
		wheels.push(
			carModel.getObjectByName('Rear_weels_1'),
			carModel.getObjectByName('front_weels_2')
		);
		
		carRef.value = carModel;
		console.log('carModel:');
		console.log(carModel);
		scene.add(carModel);
	}, undefined, function (error) {
		console.log('error:');
    console.error(error);
	});
}

initGLTF();

function initOrbitControls(){
	if(cameraRef.value){
		//已初始化相机
		orbitControlsRef.value = new OrbitControls(cameraRef.value, containerRef.value);
		orbitControlsRef.value.enableDamping = true;
		orbitControlsRef.value.maxDistance = 9;
		orbitControlsRef.value.target.set(0, 0.5, 0);
		orbitControlsRef.value.update();
	}
}

function renderScene(){
	stats.update();
	requestAnimationFrame(renderScene);
	
	if(cameraRef.value){
		//已初始化相机
		rendererRef.value!.render(scene, cameraRef.value);
	}
	
	if(orbitControlsRef.value){
		//已初始化轨道控制器
		orbitControlsRef.value.update();
	}
	
	//performance.now() 方法返回一个精确到毫秒的 DOMHighResTimeStamp。
	const time = -window.performance.now() / controlRef.value.speed;
	
	for(let i = 0; i < wheels.length; i++){
		wheels[i]!.rotation.x = -(time) * Math.PI * 2;
	}
	
	grid.position.z = -(time) % 1;
}

renderScene();

const tooltip = document.createElement('div');

tooltip.className = 'car-tip';

let currentIntersected: Mesh | null = null;
// let currentIntersected;

// 创建高亮材质
const highlightMaterial = new MeshBasicMaterial({
  color: '#1ea6b9'
});

let originalMaterial: Material;
let originalColor: string;

watchEffect(() => {
	containerRef.value?.appendChild(rendererRef.value!.domElement);
	containerRef.value?.appendChild(tooltip);
	
	window.addEventListener('resize', () => {
		cameraRef.value!.aspect = window.innerWidth / window.innerHeight;
		cameraRef.value!.updateProjectionMatrix();
		rendererRef.value!.setSize(window.innerWidth, window.innerHeight);
	}, false);
	
	rendererRef.value?.domElement.addEventListener('mousemove', function(event){
		const mouse = new Vector2();
		
		mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
		mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
		
		const raycaster = new Raycaster();
		
		raycaster.setFromCamera(mouse, cameraRef.value!);
		
		const intersects = raycaster.intersectObjects(scene.children, true);
		
		if (currentIntersected) {
			//当前已有相交的物体
			currentIntersected.material = originalMaterial!;
			// currentIntersected.material.color.set(originalColor);
			currentIntersected = null;
		}
		
		if (intersects.length > 0 && intersects[0].object.type === 'Mesh') {
			//有相交的物体，最近一个相交物体的类型是 Mesh
			tooltip.style.visibility = 'visible';
			tooltip.style.left = (event.clientX + 20) + 'px';
			tooltip.style.top = (event.clientY - 20) + 'px';
			tooltip.innerHTML = intersects[0].object.name;
			// tooltip.innerHTML=`
			// <h1>哇!!!<h1>
			// `
			// 触碰变颜色
			currentIntersected = intersects[0].object as Mesh;
			originalMaterial = (intersects[0].object as Mesh).material as Material;
			// originalColor = '#' + (intersects[0].object as Mesh).material.color.getHexString();
			currentIntersected.material = highlightMaterial;
			// currentIntersected.material.color.set('#1ea6b9');
		} else {
			//没有相交的物体
			tooltip.style.visibility = 'hidden';
		}
	}, false);
});

watch(
	() => controlRef.value.detailsColor,
	(c) => detailsMaterial.color.set(c)
);

watch(
	() => controlRef.value.glassColor,
	(c) => {
		glassMaterial.color.set(c);
		(carRef.value!.getObjectByName('Object_4') as Mesh).material.color.set(c);
		(carRef.value!.getObjectByName('Object_13') as Mesh).material.color.set(c);
		(carRef.value!.getObjectByName('Object_14') as Mesh).material.color.set(c);
	}
);

watch(
	() => controlRef.value.bodyColor,
	(c) => {
		// bodyMaterial.color.set(c);
		(carRef.value!.getObjectByName('Object_7') as Mesh).material.color.set(c);
	}
);

watch(
	() => controlRef.value.showGrid,
	(b) => {
		if(b){
			//显示坐标格辅助对象
			scene.add(grid);
		}else{
			//不显示坐标格辅助对象
			scene.remove(grid);
		}
	}
);

watch(
	() => controlRef.value.playMusic,
	(newVal) => {
		if(newVal){
			//播放音乐
			audioRef.value?.play();
		}else{
			//暂停音乐
			audioRef.value?.pause();
		}
	}
);

onMounted(() => {
	// stats.dom.style.top = '50px';
	statsRef.value?.append(stats.dom);
	initScene();
	initCamera();
	initRenderer();
	initOrbitControls();
	console.log('scene.children:');
	console.log(scene.children);
});
</script>

<style>
.car-tip {
	position: absolute;
	z-index: 999;
	padding: 4px;
	background-color: #e0e7e8;
	border: solid 1px #ccc;
	visibility: hidden;
}
/* .car-player {
	display: none;
} */
</style>